========= loading data =========

m1 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID01.csv')
m2 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID02.csv')
m3 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID03.csv')
m4 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID11.csv')
m5 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID12.csv')
m6 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID13.csv')
m7 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID21.csv')
m8 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID22.csv')
m9 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID23.csv')
m10 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID29.csv')
m11 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID30.csv')
m12 = read.csv('~/Desktop/NCSA_genomics/CGManalyzer-datasets/ID31.csv')

training_frame = rbind.data.frame(
                            m1$glucoseValue,
                            m2$glucoseValue,
                            m3$glucoseValue,
                            m4$glucoseValue,
                            m5$glucoseValue,
                            m6$glucoseValue,
                            m7$glucoseValue,
                            m8$glucoseValue,
                            m9$glucoseValue,
                            m10$glucoseValue,
                            m11$glucoseValue,
                            m12$glucoseValue
                            )
training_frame

========= loading packages ===========

require(dtwclust)
Loading required package: dtwclust
Loading required package: proxy

Attaching package: ‘proxy’

The following objects are masked from ‘package:stats’:

    as.dist, dist

The following object is masked from ‘package:base’:

    as.matrix

Loading required package: dtw
Loaded dtw v1.21-3. See ?dtw for help, citation("dtw") for use in publication.

Registered S3 method overwritten by 'dplyr':
  method           from
  print.rowwise_df     
dtwclust:
Setting random number generator to L'Ecuyer-CMRG (see RNGkind()).
To read the included vignettes type: browseVignettes("dtwclust").
See news(package = "dtwclust") after package updates.
require(mcclust)
Loading required package: mcclust
Loading required package: lpSolve
require(ClusterR)
Loading required package: ClusterR
Loading required package: gtools

======== HIERARCHICAL => Raw ===========

clust.hier_raw <- tsclust(training_frame, type = "h", k = 4L, distance = "dtw2", trace=TRUE, control = hierarchical_control(method = "ward.D"))

Calculating distance matrix...
Performing hierarchical clustering...
Extracting centroids...

    Elapsed time is 123.901 seconds.
plot(clust.hier_raw, type="sc")

plot(clust.hier_raw)

t(cbind(training_frame[,0], cluster = clust.hier_raw@cluster))
        1 2 3 4 5 6 7 8 9 10 11 12
cluster 1 1 2 3 3 3 1 4 3  4  4  4
l_hier <- clust.hier_raw@cluster
m_hier <- c(1,1,1,3,3,3,2,2,2,4,4,4)
plot(range(1:12),range(1:4), type='n')
points(m_hier, col='red')
lines(l_hier, col='green')

predict(clust.hier_raw,newdata=unlist(m3$glucoseValue))
[1] 2
predict(clust.hier_raw,newdata=unlist(m6$glucoseValue))
[1] 3
predict(clust.hier_raw,newdata=unlist(m9$glucoseValue))
[1] 3
predict(clust.hier_raw,newdata=unlist(m12$glucoseValue))
[1] 4
index_hier_raw=mclust::adjustedRandIndex(l_hier,m_hier)
unadjusted_hier_raw=mclust::adjustedRandIndex(l_hier,m_hier)
index_hier_raw
[1] 0.3966245
unadjusted_hier_raw
[1] 0.3966245

=========== Partitional => Raw ===========

clust.par_raw <- tsclust(training_frame, type = "partitional", k = 4L, distance = "dtw2", trace=TRUE)

    Precomputing distance matrix...

Iteration 1: Changes / Distsum = 12 / 753.607
Iteration 2: Changes / Distsum = 3 / 713.3609
Iteration 3: Changes / Distsum = 1 / 675.1262
Iteration 4: Changes / Distsum = 1 / 638.8285
Iteration 5: Changes / Distsum = 1 / 552.4629
Iteration 6: Changes / Distsum = 0 / 552.4629

    Elapsed time is 59.164 seconds.
plot(clust.par_raw, type="sc")

t(cbind(training_frame[,0], cluster = clust.par_raw@cluster))
        [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
cluster    4    1    3    4    4    2    1    2    4     2     2     2
l_par <- clust.par_raw@cluster
m_par <- c(4,4,4,1,1,1,2,2,2,3,3,3)
plot(range(1:12),range(1:4), type='n')
points(m_par, col='red')
lines(l_par, col='green')

predict(clust.par_raw,newdata=unlist(m3$glucoseValue))
[1] 3
predict(clust.par_raw,newdata=unlist(m6$glucoseValue))
[1] 4
predict(clust.par_raw,newdata=unlist(m9$glucoseValue))
[1] 4
predict(clust.par_raw,newdata=unlist(m12$glucoseValue))
[1] 1
index_par_raw=mclust::adjustedRandIndex(l_par,m_par)
unadjusted_par_raw=mclust::adjustedRandIndex(l_par,m_par)
index_par_raw
[1] 0.07968127
unadjusted_par_raw
[1] 0.07968127

========== K Means => Raw ===========

kmeans_cluster_raw = KMeans_rcpp(training_frame,clusters=4)
l_kmeans_raw = kmeans_cluster_raw$cluster
l_kmeans_raw
 [1] 3 4 1 2 2 4 3 4 2 4 4 4
m_kmeans_raw <- c(1,1,1,2,2,2,3,3,3,4,4,4)

index_kmeans_raw = mclust::adjustedRandIndex(l_kmeans_raw,m_kmeans_raw)
unadjusted_kmeans_raw = mclust::adjustedRandIndex(l_kmeans_raw,m_kmeans_raw)
index_kmeans_raw
[1] 0.04528302
unadjusted_kmeans_raw
[1] 0.04528302

========== Linear Scaling ============

linearScaling = function(data){
  scaled = c()
  for (i in 1:length(data)) {
    scaled[i] = (data[i]-min(data))/(max(data)-min(data))
    #print(scaled[i])
  }
  return(scaled)
}


training_frame_scaled<-rbind.data.frame(
  linearScaling(m1$glucoseValue),
  linearScaling(m2$glucoseValue),
  linearScaling(m3$glucoseValue),
  linearScaling(m4$glucoseValue),
  linearScaling(m5$glucoseValue),
  linearScaling(m6$glucoseValue),
  linearScaling(m7$glucoseValue),
  linearScaling(m8$glucoseValue),
  linearScaling(m9$glucoseValue),
  linearScaling(m10$glucoseValue),
  linearScaling(m11$glucoseValue),
  linearScaling(m12$glucoseValue)
)
training_frame_scaled

======== HIERARCHICAL => Scaled ===========

clust.hier_scaled <- tsclust(training_frame_scaled, type = "h", k = 4L, distance = "dtw2", trace=TRUE, control = hierarchical_control(method = "ward.D"))

Calculating distance matrix...
Performing hierarchical clustering...
Extracting centroids...

    Elapsed time is 99.104 seconds.
plot(clust.hier_scaled, type="sc")

plot(clust.hier_scaled)

t(cbind(training_frame_scaled[,0], cluster = clust.hier_scaled@cluster))
        1 2 3 4 5 6 7 8 9 10 11 12
cluster 1 2 3 4 2 4 2 4 3  4  4  4
l_hier <- clust.hier_scaled@cluster
m_hier <- c(1,1,1,3,3,3,2,2,2,4,4,4)
plot(range(1:12),range(1:4), type='n')
points(m_hier, col='red')
lines(l_hier, col='green')

predict(clust.hier_scaled,newdata=unlist(linearScaling(m3$glucoseValue)))
[1] 3
predict(clust.hier_scaled,newdata=unlist(linearScaling(m6$glucoseValue)))
[1] 3
predict(clust.hier_scaled,newdata=unlist(linearScaling(m9$glucoseValue)))
[1] 3
predict(clust.hier_scaled,newdata=unlist(linearScaling(m12$glucoseValue)))
[1] 3
index_hier_scaled=mclust::adjustedRandIndex(l_hier,m_hier)
unadjusted_hier_scaled=mclust::adjustedRandIndex(l_hier,m_hier)
index_hier_scaled
[1] 0.04528302
unadjusted_hier_scaled
[1] 0.04528302

=========== Partitional => Scaled ===========

clust.par_scaled <- tsclust(training_frame_scaled, type = "partitional", k = 4L, distance = "dtw2", trace=TRUE)

    Precomputing distance matrix...

Iteration 1: Changes / Distsum = 12 / 37.12822
Iteration 2: Changes / Distsum = 1 / 32.85783
Iteration 3: Changes / Distsum = 0 / 32.85783

    Elapsed time is 58.337 seconds.
plot(clust.par_scaled, type="sc")

t(cbind(training_frame_scaled[,0], cluster = clust.par_scaled@cluster))
        [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
cluster    3    2    4    1    2    1    2    1    2     1     4     4
l_par <- clust.par_scaled@cluster
m_par <- c(3,3,3,1,1,1,2,2,2,4,4,4)
plot(range(1:12),range(1:4), type='n')
points(m_par, col='red')
lines(l_par, col='green')

predict(clust.par_raw,newdata=unlist(linearScaling(m3$glucoseValue)))
[1] 1
predict(clust.par_raw,newdata=unlist(linearScaling(m6$glucoseValue)))
[1] 1
predict(clust.par_raw,newdata=unlist(linearScaling(m9$glucoseValue)))
[1] 1
predict(clust.par_raw,newdata=unlist(linearScaling(m12$glucoseValue)))
[1] 1
index_par_scaled=mclust::adjustedRandIndex(l_par,m_par)
unadjusted_par_scaled=mclust::adjustedRandIndex(l_par,m_par)
index_par_scaled
[1] 0.02531646
unadjusted_par_scaled
[1] 0.02531646

========== K Means => Scaled ===========

kmeans_cluster_scaled = KMeans_rcpp(training_frame_scaled,clusters=4)
l_kmeans_scaled = kmeans_cluster_scaled$cluster
l_kmeans_scaled
 [1] 3 2 3 1 2 1 3 4 4 2 1 4
m_kmeans_scaled <- c(3,3,3,2,2,2,4,4,4,1,1,1)

index_kmeans_scaled = mclust::adjustedRandIndex(l_kmeans_scaled,m_kmeans_scaled)
unadjusted_kmeans_scaled = mclust::adjustedRandIndex(l_kmeans_scaled,m_kmeans_scaled)
index_kmeans_scaled
[1] 0.08333333
unadjusted_kmeans_scaled
[1] 0.08333333

=========== Z Score Normalization =============

training_frame_zscore<-rbind.data.frame(
  zscore(m1$glucoseValue),
  zscore(m2$glucoseValue),
  zscore(m3$glucoseValue),
  zscore(m4$glucoseValue),
  zscore(m5$glucoseValue),
  zscore(m6$glucoseValue),
  zscore(m7$glucoseValue),
  zscore(m8$glucoseValue),
  zscore(m9$glucoseValue),
  zscore(m10$glucoseValue),
  zscore(m11$glucoseValue),
  zscore(m12$glucoseValue)
)
training_frame_zscore

======== HIERARCHICAL => Z score ===========

clust.hier_zscore <- tsclust(training_frame_zscore, type = "h", k = 4L, distance = "dtw2", trace=TRUE, control = hierarchical_control(method = "ward.D"))

Calculating distance matrix...
Performing hierarchical clustering...
Extracting centroids...

    Elapsed time is 95.03 seconds.
plot(clust.hier_zscore, type="sc")

plot(clust.hier_zscore)

t(cbind(training_frame_zscore[,0], cluster = clust.hier_zscore@cluster))
        1 2 3 4 5 6 7 8 9 10 11 12
cluster 1 1 2 3 1 3 1 3 4  4  4  2
l_hier <- clust.hier_zscore@cluster
m_hier <- c(1,1,1,3,3,3,2,2,2,4,4,4)
plot(range(1:12),range(1:4), type='n')
points(m_hier, col='red')
lines(l_hier, col='green')

predict(clust.hier_zscore,newdata=unlist(zscore(m3$glucoseValue)))
[1] 2
predict(clust.hier_zscore,newdata=unlist(zscore(m6$glucoseValue)))
[1] 2
predict(clust.hier_zscore,newdata=unlist(zscore(m9$glucoseValue)))
[1] 4
predict(clust.hier_zscore,newdata=unlist(zscore(m12$glucoseValue)))
[1] 2
index_hier_zscore=mclust::adjustedRandIndex(l_hier,m_hier)
unadjusted_hier_zscore=mclust::adjustedRandIndex(l_hier,m_hier)
index_hier_zscore
[1] 0.06278027
unadjusted_hier_zscore
[1] 0.06278027

=========== Partitional => Zscore ===========

clust.par_zscore <- tsclust(training_frame_zscore, type = "partitional", k = 4L, distance = "dtw2", trace=TRUE)

    Precomputing distance matrix...

Iteration 1: Changes / Distsum = 12 / 199.0184
Iteration 2: Changes / Distsum = 2 / 192.3014
Iteration 3: Changes / Distsum = 1 / 161.7827
Iteration 4: Changes / Distsum = 0 / 161.7827

    Elapsed time is 56.557 seconds.
plot(clust.par_zscore, type="sc")

t(cbind(training_frame_zscore[,0], cluster = clust.par_zscore@cluster))
        [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
cluster    3    2    1    1    2    1    2    1    2     4     4     1
l_par <- clust.par_zscore@cluster
m_par <- c(3,3,3,1,1,1,2,2,2,4,4,4)
plot(range(1:12),range(1:4), type='n')
points(m_par, col='red')
lines(l_par, col='green')

predict(clust.par_zscore,newdata=unlist(zscore(m3$glucoseValue)))
[1] 1
predict(clust.par_zscore,newdata=unlist(zscore(m6$glucoseValue)))
[1] 2
predict(clust.par_zscore,newdata=unlist(zscore(m9$glucoseValue)))
[1] 2
predict(clust.par_zscore,newdata=unlist(zscore(m12$glucoseValue)))
[1] 1
index_par_zscore=mclust::adjustedRandIndex(l_par,m_par)
unadjusted_par_zscore=mclust::adjustedRandIndex(l_par,m_par)
index_par_zscore
[1] -0.007968127
unadjusted_par_zscore
[1] -0.007968127

========== K Means => Zscore ===========

kmeans_cluster_zscore = KMeans_rcpp(training_frame_zscore,clusters=4)
l_kmeans_zscore = kmeans_cluster_zscore$cluster
l_kmeans_zscore
 [1] 3 2 2 1 2 1 3 4 2 2 1 4
m_kmeans_zscore <- c(2,2,2,3,3,3,4,4,4,1,1,1)
index_kmeans_zscore = mclust::adjustedRandIndex(l_kmeans_scaled,m_kmeans_scaled)
unadjusted_kmeans_zscore = mclust::adjustedRandIndex(l_kmeans_scaled,m_kmeans_scaled)
index_kmeans_zscore
[1] 0.08333333
unadjusted_kmeans_zscore
[1] 0.08333333

=========Plotting============

colors = c('red','blue','green')
c_types = c('Hierarchical Clustering','Partitional Clustering','K Means Clustering')
t_types = c('Raw', 'Min-Max Scaling','Z-Score Normalization')
index_all = c(index_hier_raw,index_hier_scaled,index_hier_zscore, index_par_raw, index_par_scaled, index_par_zscore, index_kmeans_raw, index_kmeans_scaled, index_kmeans_zscore)

plot(index_all,xaxt='n',type='h', col = colors, xlab="Clustering Methods", ylab="ARANDI Measure", main='Adjusted Random Index: Hierarchical, Partitional & K-Means Clustering', lwd=4)
axis(1, at=seq(2,9,by=3), labels=c_types[1:3])
legend("topright",t_types, col = colors, title = 'Transformation Types', lwd=2,cex=.75)

unadjusted_all = c(unadjusted_hier_raw, unadjusted_hier_scaled, unadjusted_hier_zscore, unadjusted_par_raw, unadjusted_par_scaled, unadjusted_par_zscore, unadjusted_kmeans_raw, unadjusted_kmeans_scaled, unadjusted_kmeans_zscore)

plot(unadjusted_all,xaxt='n',type='h', col = colors, xlab="Clustering Methods", ylab="Unadjusted Random Index", main='Unadjusted Index: Hierarchical, Partitional & K-Means Clustering', lwd=4)
axis(1, at=seq(2,9,by=3), labels=c_types[1:3])
legend("topright",t_types, col = colors, title = 'Transformation Types', lwd=2, cex=0.75)

LS0tCnRpdGxlOiAiY2dtYW5hbHlzZXJEVFciCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KPT09PT09PT09IGxvYWRpbmcgZGF0YSA9PT09PT09PT0KYGBge3J9Cm0xID0gcmVhZC5jc3YoJ34vRGVza3RvcC9OQ1NBX2dlbm9taWNzL0NHTWFuYWx5emVyLWRhdGFzZXRzL0lEMDEuY3N2JykKbTIgPSByZWFkLmNzdignfi9EZXNrdG9wL05DU0FfZ2Vub21pY3MvQ0dNYW5hbHl6ZXItZGF0YXNldHMvSUQwMi5jc3YnKQptMyA9IHJlYWQuY3N2KCd+L0Rlc2t0b3AvTkNTQV9nZW5vbWljcy9DR01hbmFseXplci1kYXRhc2V0cy9JRDAzLmNzdicpCm00ID0gcmVhZC5jc3YoJ34vRGVza3RvcC9OQ1NBX2dlbm9taWNzL0NHTWFuYWx5emVyLWRhdGFzZXRzL0lEMTEuY3N2JykKbTUgPSByZWFkLmNzdignfi9EZXNrdG9wL05DU0FfZ2Vub21pY3MvQ0dNYW5hbHl6ZXItZGF0YXNldHMvSUQxMi5jc3YnKQptNiA9IHJlYWQuY3N2KCd+L0Rlc2t0b3AvTkNTQV9nZW5vbWljcy9DR01hbmFseXplci1kYXRhc2V0cy9JRDEzLmNzdicpCm03ID0gcmVhZC5jc3YoJ34vRGVza3RvcC9OQ1NBX2dlbm9taWNzL0NHTWFuYWx5emVyLWRhdGFzZXRzL0lEMjEuY3N2JykKbTggPSByZWFkLmNzdignfi9EZXNrdG9wL05DU0FfZ2Vub21pY3MvQ0dNYW5hbHl6ZXItZGF0YXNldHMvSUQyMi5jc3YnKQptOSA9IHJlYWQuY3N2KCd+L0Rlc2t0b3AvTkNTQV9nZW5vbWljcy9DR01hbmFseXplci1kYXRhc2V0cy9JRDIzLmNzdicpCm0xMCA9IHJlYWQuY3N2KCd+L0Rlc2t0b3AvTkNTQV9nZW5vbWljcy9DR01hbmFseXplci1kYXRhc2V0cy9JRDI5LmNzdicpCm0xMSA9IHJlYWQuY3N2KCd+L0Rlc2t0b3AvTkNTQV9nZW5vbWljcy9DR01hbmFseXplci1kYXRhc2V0cy9JRDMwLmNzdicpCm0xMiA9IHJlYWQuY3N2KCd+L0Rlc2t0b3AvTkNTQV9nZW5vbWljcy9DR01hbmFseXplci1kYXRhc2V0cy9JRDMxLmNzdicpCgp0cmFpbmluZ19mcmFtZSA9IHJiaW5kLmRhdGEuZnJhbWUoCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtMSRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtMiRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtMyRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtNCRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtNSRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtNiRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtNyRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtOCRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtOSRnbHVjb3NlVmFsdWUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtMTAkZ2x1Y29zZVZhbHVlLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgbTExJGdsdWNvc2VWYWx1ZSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIG0xMiRnbHVjb3NlVmFsdWUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICkKdHJhaW5pbmdfZnJhbWUKYGBgCgo9PT09PT09PT0gbG9hZGluZyBwYWNrYWdlcyA9PT09PT09PT09PQpgYGB7cn0KcmVxdWlyZShkdHdjbHVzdCkKcmVxdWlyZShtY2NsdXN0KQpyZXF1aXJlKENsdXN0ZXJSKQpgYGAKCgoKCj09PT09PT09IEhJRVJBUkNISUNBTCA9PiBSYXcgPT09PT09PT09PT0KYGBge3J9CmNsdXN0LmhpZXJfcmF3IDwtIHRzY2x1c3QodHJhaW5pbmdfZnJhbWUsIHR5cGUgPSAiaCIsIGsgPSA0TCwgZGlzdGFuY2UgPSAiZHR3MiIsIHRyYWNlPVRSVUUsIGNvbnRyb2wgPSBoaWVyYXJjaGljYWxfY29udHJvbChtZXRob2QgPSAid2FyZC5EIikpCgpwbG90KGNsdXN0LmhpZXJfcmF3LCB0eXBlPSJzYyIpCmBgYAoKYGBge3J9CnBsb3QoY2x1c3QuaGllcl9yYXcpCmBgYAoKCmBgYHtyfQp0KGNiaW5kKHRyYWluaW5nX2ZyYW1lWywwXSwgY2x1c3RlciA9IGNsdXN0LmhpZXJfcmF3QGNsdXN0ZXIpKQpgYGAKCmBgYHtyfQpsX2hpZXIgPC0gY2x1c3QuaGllcl9yYXdAY2x1c3RlcgptX2hpZXIgPC0gYygxLDEsMSwzLDMsMywyLDIsMiw0LDQsNCkKYGBgCgpgYGB7cn0KcGxvdChyYW5nZSgxOjEyKSxyYW5nZSgxOjQpLCB0eXBlPSduJykKcG9pbnRzKG1faGllciwgY29sPSdyZWQnKQpsaW5lcyhsX2hpZXIsIGNvbD0nZ3JlZW4nKQpgYGAKYGBge3J9CnByZWRpY3QoY2x1c3QuaGllcl9yYXcsbmV3ZGF0YT11bmxpc3QobTMkZ2x1Y29zZVZhbHVlKSkKcHJlZGljdChjbHVzdC5oaWVyX3JhdyxuZXdkYXRhPXVubGlzdChtNiRnbHVjb3NlVmFsdWUpKQpwcmVkaWN0KGNsdXN0LmhpZXJfcmF3LG5ld2RhdGE9dW5saXN0KG05JGdsdWNvc2VWYWx1ZSkpCnByZWRpY3QoY2x1c3QuaGllcl9yYXcsbmV3ZGF0YT11bmxpc3QobTEyJGdsdWNvc2VWYWx1ZSkpCmBgYApgYGB7cn0KaW5kZXhfaGllcl9yYXc9bWNsdXN0OjphZGp1c3RlZFJhbmRJbmRleChsX2hpZXIsbV9oaWVyKQp1bmFkanVzdGVkX2hpZXJfcmF3PW1jbHVzdDo6YWRqdXN0ZWRSYW5kSW5kZXgobF9oaWVyLG1faGllcikKaW5kZXhfaGllcl9yYXcKdW5hZGp1c3RlZF9oaWVyX3JhdwpgYGAKCgoKPT09PT09PT09PT0gUGFydGl0aW9uYWwgPT4gUmF3ID09PT09PT09PT09CmBgYHtyfQpjbHVzdC5wYXJfcmF3IDwtIHRzY2x1c3QodHJhaW5pbmdfZnJhbWUsIHR5cGUgPSAicGFydGl0aW9uYWwiLCBrID0gNEwsIGRpc3RhbmNlID0gImR0dzIiLCB0cmFjZT1UUlVFKQoKcGxvdChjbHVzdC5wYXJfcmF3LCB0eXBlPSJzYyIpCmBgYAoKCgoKYGBge3J9CnQoY2JpbmQodHJhaW5pbmdfZnJhbWVbLDBdLCBjbHVzdGVyID0gY2x1c3QucGFyX3Jhd0BjbHVzdGVyKSkKYGBgCgpgYGB7cn0KbF9wYXIgPC0gY2x1c3QucGFyX3Jhd0BjbHVzdGVyCm1fcGFyIDwtIGMoNCw0LDQsMSwxLDEsMiwyLDIsMywzLDMpCmBgYAoKYGBge3J9CnBsb3QocmFuZ2UoMToxMikscmFuZ2UoMTo0KSwgdHlwZT0nbicpCnBvaW50cyhtX3BhciwgY29sPSdyZWQnKQpsaW5lcyhsX3BhciwgY29sPSdncmVlbicpCmBgYAoKYGBge3J9CnByZWRpY3QoY2x1c3QucGFyX3JhdyxuZXdkYXRhPXVubGlzdChtMyRnbHVjb3NlVmFsdWUpKQpwcmVkaWN0KGNsdXN0LnBhcl9yYXcsbmV3ZGF0YT11bmxpc3QobTYkZ2x1Y29zZVZhbHVlKSkKcHJlZGljdChjbHVzdC5wYXJfcmF3LG5ld2RhdGE9dW5saXN0KG05JGdsdWNvc2VWYWx1ZSkpCnByZWRpY3QoY2x1c3QucGFyX3JhdyxuZXdkYXRhPXVubGlzdChtMTIkZ2x1Y29zZVZhbHVlKSkKYGBgCgpgYGB7cn0KaW5kZXhfcGFyX3Jhdz1tY2x1c3Q6OmFkanVzdGVkUmFuZEluZGV4KGxfcGFyLG1fcGFyKQp1bmFkanVzdGVkX3Bhcl9yYXc9bWNsdXN0OjphZGp1c3RlZFJhbmRJbmRleChsX3BhcixtX3BhcikKaW5kZXhfcGFyX3Jhdwp1bmFkanVzdGVkX3Bhcl9yYXcKYGBgCgoKCgoKCgoKPT09PT09PT09PSBLIE1lYW5zID0+IFJhdyA9PT09PT09PT09PQpgYGB7cn0Ka21lYW5zX2NsdXN0ZXJfcmF3ID0gS01lYW5zX3JjcHAodHJhaW5pbmdfZnJhbWUsY2x1c3RlcnM9NCkKbF9rbWVhbnNfcmF3ID0ga21lYW5zX2NsdXN0ZXJfcmF3JGNsdXN0ZXIKbF9rbWVhbnNfcmF3Cm1fa21lYW5zX3JhdyA8LSBjKDEsMSwxLDIsMiwyLDMsMywzLDQsNCw0KQpgYGAKCmBgYHtyfQoKaW5kZXhfa21lYW5zX3JhdyA9IG1jbHVzdDo6YWRqdXN0ZWRSYW5kSW5kZXgobF9rbWVhbnNfcmF3LG1fa21lYW5zX3JhdykKdW5hZGp1c3RlZF9rbWVhbnNfcmF3ID0gbWNsdXN0OjphZGp1c3RlZFJhbmRJbmRleChsX2ttZWFuc19yYXcsbV9rbWVhbnNfcmF3KQppbmRleF9rbWVhbnNfcmF3CnVuYWRqdXN0ZWRfa21lYW5zX3JhdwpgYGAKCgo9PT09PT09PT09IExpbmVhciBTY2FsaW5nID09PT09PT09PT09PQpgYGB7cn0KbGluZWFyU2NhbGluZyA9IGZ1bmN0aW9uKGRhdGEpewogIHNjYWxlZCA9IGMoKQogIGZvciAoaSBpbiAxOmxlbmd0aChkYXRhKSkgewogICAgc2NhbGVkW2ldID0gKGRhdGFbaV0tbWluKGRhdGEpKS8obWF4KGRhdGEpLW1pbihkYXRhKSkKICAgICNwcmludChzY2FsZWRbaV0pCiAgfQogIHJldHVybihzY2FsZWQpCn0KCgp0cmFpbmluZ19mcmFtZV9zY2FsZWQ8LXJiaW5kLmRhdGEuZnJhbWUoCiAgbGluZWFyU2NhbGluZyhtMSRnbHVjb3NlVmFsdWUpLAogIGxpbmVhclNjYWxpbmcobTIkZ2x1Y29zZVZhbHVlKSwKICBsaW5lYXJTY2FsaW5nKG0zJGdsdWNvc2VWYWx1ZSksCiAgbGluZWFyU2NhbGluZyhtNCRnbHVjb3NlVmFsdWUpLAogIGxpbmVhclNjYWxpbmcobTUkZ2x1Y29zZVZhbHVlKSwKICBsaW5lYXJTY2FsaW5nKG02JGdsdWNvc2VWYWx1ZSksCiAgbGluZWFyU2NhbGluZyhtNyRnbHVjb3NlVmFsdWUpLAogIGxpbmVhclNjYWxpbmcobTgkZ2x1Y29zZVZhbHVlKSwKICBsaW5lYXJTY2FsaW5nKG05JGdsdWNvc2VWYWx1ZSksCiAgbGluZWFyU2NhbGluZyhtMTAkZ2x1Y29zZVZhbHVlKSwKICBsaW5lYXJTY2FsaW5nKG0xMSRnbHVjb3NlVmFsdWUpLAogIGxpbmVhclNjYWxpbmcobTEyJGdsdWNvc2VWYWx1ZSkKKQp0cmFpbmluZ19mcmFtZV9zY2FsZWQKYGBgCgoKCj09PT09PT09IEhJRVJBUkNISUNBTCA9PiBTY2FsZWQgPT09PT09PT09PT0KYGBge3J9CmNsdXN0LmhpZXJfc2NhbGVkIDwtIHRzY2x1c3QodHJhaW5pbmdfZnJhbWVfc2NhbGVkLCB0eXBlID0gImgiLCBrID0gNEwsIGRpc3RhbmNlID0gImR0dzIiLCB0cmFjZT1UUlVFLCBjb250cm9sID0gaGllcmFyY2hpY2FsX2NvbnRyb2wobWV0aG9kID0gIndhcmQuRCIpKQoKcGxvdChjbHVzdC5oaWVyX3NjYWxlZCwgdHlwZT0ic2MiKQpgYGAKCmBgYHtyfQpwbG90KGNsdXN0LmhpZXJfc2NhbGVkKQpgYGAKCgpgYGB7cn0KdChjYmluZCh0cmFpbmluZ19mcmFtZV9zY2FsZWRbLDBdLCBjbHVzdGVyID0gY2x1c3QuaGllcl9zY2FsZWRAY2x1c3RlcikpCmBgYAoKYGBge3J9CmxfaGllciA8LSBjbHVzdC5oaWVyX3NjYWxlZEBjbHVzdGVyCm1faGllciA8LSBjKDEsMSwxLDMsMywzLDIsMiwyLDQsNCw0KQpgYGAKCmBgYHtyfQpwbG90KHJhbmdlKDE6MTIpLHJhbmdlKDE6NCksIHR5cGU9J24nKQpwb2ludHMobV9oaWVyLCBjb2w9J3JlZCcpCmxpbmVzKGxfaGllciwgY29sPSdncmVlbicpCmBgYApgYGB7cn0KcHJlZGljdChjbHVzdC5oaWVyX3NjYWxlZCxuZXdkYXRhPXVubGlzdChsaW5lYXJTY2FsaW5nKG0zJGdsdWNvc2VWYWx1ZSkpKQpwcmVkaWN0KGNsdXN0LmhpZXJfc2NhbGVkLG5ld2RhdGE9dW5saXN0KGxpbmVhclNjYWxpbmcobTYkZ2x1Y29zZVZhbHVlKSkpCnByZWRpY3QoY2x1c3QuaGllcl9zY2FsZWQsbmV3ZGF0YT11bmxpc3QobGluZWFyU2NhbGluZyhtOSRnbHVjb3NlVmFsdWUpKSkKcHJlZGljdChjbHVzdC5oaWVyX3NjYWxlZCxuZXdkYXRhPXVubGlzdChsaW5lYXJTY2FsaW5nKG0xMiRnbHVjb3NlVmFsdWUpKSkKYGBgCmBgYHtyfQppbmRleF9oaWVyX3NjYWxlZD1tY2x1c3Q6OmFkanVzdGVkUmFuZEluZGV4KGxfaGllcixtX2hpZXIpCnVuYWRqdXN0ZWRfaGllcl9zY2FsZWQ9bWNsdXN0OjphZGp1c3RlZFJhbmRJbmRleChsX2hpZXIsbV9oaWVyKQppbmRleF9oaWVyX3NjYWxlZAp1bmFkanVzdGVkX2hpZXJfc2NhbGVkCmBgYAoKCgo9PT09PT09PT09PSBQYXJ0aXRpb25hbCA9PiBTY2FsZWQgPT09PT09PT09PT0KCmBgYHtyfQpjbHVzdC5wYXJfc2NhbGVkIDwtIHRzY2x1c3QodHJhaW5pbmdfZnJhbWVfc2NhbGVkLCB0eXBlID0gInBhcnRpdGlvbmFsIiwgayA9IDRMLCBkaXN0YW5jZSA9ICJkdHcyIiwgdHJhY2U9VFJVRSkKCnBsb3QoY2x1c3QucGFyX3NjYWxlZCwgdHlwZT0ic2MiKQpgYGAKCgoKCmBgYHtyfQp0KGNiaW5kKHRyYWluaW5nX2ZyYW1lX3NjYWxlZFssMF0sIGNsdXN0ZXIgPSBjbHVzdC5wYXJfc2NhbGVkQGNsdXN0ZXIpKQpgYGAKCmBgYHtyfQpsX3BhciA8LSBjbHVzdC5wYXJfc2NhbGVkQGNsdXN0ZXIKbV9wYXIgPC0gYygzLDMsMywxLDEsMSwyLDIsMiw0LDQsNCkKYGBgCgpgYGB7cn0KcGxvdChyYW5nZSgxOjEyKSxyYW5nZSgxOjQpLCB0eXBlPSduJykKcG9pbnRzKG1fcGFyLCBjb2w9J3JlZCcpCmxpbmVzKGxfcGFyLCBjb2w9J2dyZWVuJykKYGBgCgpgYGB7cn0KcHJlZGljdChjbHVzdC5wYXJfcmF3LG5ld2RhdGE9dW5saXN0KGxpbmVhclNjYWxpbmcobTMkZ2x1Y29zZVZhbHVlKSkpCnByZWRpY3QoY2x1c3QucGFyX3JhdyxuZXdkYXRhPXVubGlzdChsaW5lYXJTY2FsaW5nKG02JGdsdWNvc2VWYWx1ZSkpKQpwcmVkaWN0KGNsdXN0LnBhcl9yYXcsbmV3ZGF0YT11bmxpc3QobGluZWFyU2NhbGluZyhtOSRnbHVjb3NlVmFsdWUpKSkKcHJlZGljdChjbHVzdC5wYXJfcmF3LG5ld2RhdGE9dW5saXN0KGxpbmVhclNjYWxpbmcobTEyJGdsdWNvc2VWYWx1ZSkpKQpgYGAKCmBgYHtyfQppbmRleF9wYXJfc2NhbGVkPW1jbHVzdDo6YWRqdXN0ZWRSYW5kSW5kZXgobF9wYXIsbV9wYXIpCnVuYWRqdXN0ZWRfcGFyX3NjYWxlZD1tY2x1c3Q6OmFkanVzdGVkUmFuZEluZGV4KGxfcGFyLG1fcGFyKQppbmRleF9wYXJfc2NhbGVkCnVuYWRqdXN0ZWRfcGFyX3NjYWxlZApgYGAKCgo9PT09PT09PT09IEsgTWVhbnMgPT4gU2NhbGVkID09PT09PT09PT09CmBgYHtyfQprbWVhbnNfY2x1c3Rlcl9zY2FsZWQgPSBLTWVhbnNfcmNwcCh0cmFpbmluZ19mcmFtZV9zY2FsZWQsY2x1c3RlcnM9NCkKbF9rbWVhbnNfc2NhbGVkID0ga21lYW5zX2NsdXN0ZXJfc2NhbGVkJGNsdXN0ZXIKbF9rbWVhbnNfc2NhbGVkCm1fa21lYW5zX3NjYWxlZCA8LSBjKDMsMywzLDIsMiwyLDQsNCw0LDEsMSwxKQpgYGAKCmBgYHtyfQoKaW5kZXhfa21lYW5zX3NjYWxlZCA9IG1jbHVzdDo6YWRqdXN0ZWRSYW5kSW5kZXgobF9rbWVhbnNfc2NhbGVkLG1fa21lYW5zX3NjYWxlZCkKdW5hZGp1c3RlZF9rbWVhbnNfc2NhbGVkID0gbWNsdXN0OjphZGp1c3RlZFJhbmRJbmRleChsX2ttZWFuc19zY2FsZWQsbV9rbWVhbnNfc2NhbGVkKQppbmRleF9rbWVhbnNfc2NhbGVkCnVuYWRqdXN0ZWRfa21lYW5zX3NjYWxlZApgYGAKCgoKCgoKCgo9PT09PT09PT09PSBaIFNjb3JlIE5vcm1hbGl6YXRpb24gPT09PT09PT09PT09PQpgYGB7cn0KdHJhaW5pbmdfZnJhbWVfenNjb3JlPC1yYmluZC5kYXRhLmZyYW1lKAogIHpzY29yZShtMSRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtMiRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtMyRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtNCRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtNSRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtNiRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtNyRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtOCRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtOSRnbHVjb3NlVmFsdWUpLAogIHpzY29yZShtMTAkZ2x1Y29zZVZhbHVlKSwKICB6c2NvcmUobTExJGdsdWNvc2VWYWx1ZSksCiAgenNjb3JlKG0xMiRnbHVjb3NlVmFsdWUpCikKdHJhaW5pbmdfZnJhbWVfenNjb3JlCmBgYAoKCj09PT09PT09IEhJRVJBUkNISUNBTCA9PiBaIHNjb3JlID09PT09PT09PT09CmBgYHtyfQpjbHVzdC5oaWVyX3pzY29yZSA8LSB0c2NsdXN0KHRyYWluaW5nX2ZyYW1lX3pzY29yZSwgdHlwZSA9ICJoIiwgayA9IDRMLCBkaXN0YW5jZSA9ICJkdHcyIiwgdHJhY2U9VFJVRSwgY29udHJvbCA9IGhpZXJhcmNoaWNhbF9jb250cm9sKG1ldGhvZCA9ICJ3YXJkLkQiKSkKCnBsb3QoY2x1c3QuaGllcl96c2NvcmUsIHR5cGU9InNjIikKYGBgCgpgYGB7cn0KcGxvdChjbHVzdC5oaWVyX3pzY29yZSkKYGBgCgoKYGBge3J9CnQoY2JpbmQodHJhaW5pbmdfZnJhbWVfenNjb3JlWywwXSwgY2x1c3RlciA9IGNsdXN0LmhpZXJfenNjb3JlQGNsdXN0ZXIpKQpgYGAKCmBgYHtyfQpsX2hpZXIgPC0gY2x1c3QuaGllcl96c2NvcmVAY2x1c3RlcgptX2hpZXIgPC0gYygxLDEsMSwzLDMsMywyLDIsMiw0LDQsNCkKYGBgCgpgYGB7cn0KcGxvdChyYW5nZSgxOjEyKSxyYW5nZSgxOjQpLCB0eXBlPSduJykKcG9pbnRzKG1faGllciwgY29sPSdyZWQnKQpsaW5lcyhsX2hpZXIsIGNvbD0nZ3JlZW4nKQpgYGAKYGBge3J9CnByZWRpY3QoY2x1c3QuaGllcl96c2NvcmUsbmV3ZGF0YT11bmxpc3QoenNjb3JlKG0zJGdsdWNvc2VWYWx1ZSkpKQpwcmVkaWN0KGNsdXN0LmhpZXJfenNjb3JlLG5ld2RhdGE9dW5saXN0KHpzY29yZShtNiRnbHVjb3NlVmFsdWUpKSkKcHJlZGljdChjbHVzdC5oaWVyX3pzY29yZSxuZXdkYXRhPXVubGlzdCh6c2NvcmUobTkkZ2x1Y29zZVZhbHVlKSkpCnByZWRpY3QoY2x1c3QuaGllcl96c2NvcmUsbmV3ZGF0YT11bmxpc3QoenNjb3JlKG0xMiRnbHVjb3NlVmFsdWUpKSkKYGBgCmBgYHtyfQppbmRleF9oaWVyX3pzY29yZT1tY2x1c3Q6OmFkanVzdGVkUmFuZEluZGV4KGxfaGllcixtX2hpZXIpCnVuYWRqdXN0ZWRfaGllcl96c2NvcmU9bWNsdXN0OjphZGp1c3RlZFJhbmRJbmRleChsX2hpZXIsbV9oaWVyKQppbmRleF9oaWVyX3pzY29yZQp1bmFkanVzdGVkX2hpZXJfenNjb3JlCmBgYAoKCgo9PT09PT09PT09PSBQYXJ0aXRpb25hbCA9PiBac2NvcmUgPT09PT09PT09PT0KCmBgYHtyfQpjbHVzdC5wYXJfenNjb3JlIDwtIHRzY2x1c3QodHJhaW5pbmdfZnJhbWVfenNjb3JlLCB0eXBlID0gInBhcnRpdGlvbmFsIiwgayA9IDRMLCBkaXN0YW5jZSA9ICJkdHcyIiwgdHJhY2U9VFJVRSkKCnBsb3QoY2x1c3QucGFyX3pzY29yZSwgdHlwZT0ic2MiKQpgYGAKCgoKYGBge3J9CnQoY2JpbmQodHJhaW5pbmdfZnJhbWVfenNjb3JlWywwXSwgY2x1c3RlciA9IGNsdXN0LnBhcl96c2NvcmVAY2x1c3RlcikpCmBgYAoKYGBge3J9CmxfcGFyIDwtIGNsdXN0LnBhcl96c2NvcmVAY2x1c3RlcgptX3BhciA8LSBjKDMsMywzLDEsMSwxLDIsMiwyLDQsNCw0KQpgYGAKCmBgYHtyfQpwbG90KHJhbmdlKDE6MTIpLHJhbmdlKDE6NCksIHR5cGU9J24nKQpwb2ludHMobV9wYXIsIGNvbD0ncmVkJykKbGluZXMobF9wYXIsIGNvbD0nZ3JlZW4nKQpgYGAKCmBgYHtyfQpwcmVkaWN0KGNsdXN0LnBhcl96c2NvcmUsbmV3ZGF0YT11bmxpc3QoenNjb3JlKG0zJGdsdWNvc2VWYWx1ZSkpKQpwcmVkaWN0KGNsdXN0LnBhcl96c2NvcmUsbmV3ZGF0YT11bmxpc3QoenNjb3JlKG02JGdsdWNvc2VWYWx1ZSkpKQpwcmVkaWN0KGNsdXN0LnBhcl96c2NvcmUsbmV3ZGF0YT11bmxpc3QoenNjb3JlKG05JGdsdWNvc2VWYWx1ZSkpKQpwcmVkaWN0KGNsdXN0LnBhcl96c2NvcmUsbmV3ZGF0YT11bmxpc3QoenNjb3JlKG0xMiRnbHVjb3NlVmFsdWUpKSkKYGBgCgpgYGB7cn0KaW5kZXhfcGFyX3pzY29yZT1tY2x1c3Q6OmFkanVzdGVkUmFuZEluZGV4KGxfcGFyLG1fcGFyKQp1bmFkanVzdGVkX3Bhcl96c2NvcmU9bWNsdXN0OjphZGp1c3RlZFJhbmRJbmRleChsX3BhcixtX3BhcikKaW5kZXhfcGFyX3pzY29yZQp1bmFkanVzdGVkX3Bhcl96c2NvcmUKYGBgCgoKPT09PT09PT09PSBLIE1lYW5zID0+IFpzY29yZSA9PT09PT09PT09PQpgYGB7cn0Ka21lYW5zX2NsdXN0ZXJfenNjb3JlID0gS01lYW5zX3JjcHAodHJhaW5pbmdfZnJhbWVfenNjb3JlLGNsdXN0ZXJzPTQpCmxfa21lYW5zX3pzY29yZSA9IGttZWFuc19jbHVzdGVyX3pzY29yZSRjbHVzdGVyCmxfa21lYW5zX3pzY29yZQptX2ttZWFuc196c2NvcmUgPC0gYygyLDIsMiwzLDMsMyw0LDQsNCwxLDEsMSkKYGBgCgpgYGB7cn0KaW5kZXhfa21lYW5zX3pzY29yZSA9IG1jbHVzdDo6YWRqdXN0ZWRSYW5kSW5kZXgobF9rbWVhbnNfc2NhbGVkLG1fa21lYW5zX3NjYWxlZCkKdW5hZGp1c3RlZF9rbWVhbnNfenNjb3JlID0gbWNsdXN0OjphZGp1c3RlZFJhbmRJbmRleChsX2ttZWFuc19zY2FsZWQsbV9rbWVhbnNfc2NhbGVkKQppbmRleF9rbWVhbnNfenNjb3JlCnVuYWRqdXN0ZWRfa21lYW5zX3pzY29yZQpgYGAKCgo9PT09PT09PT1QbG90dGluZz09PT09PT09PT09PQpgYGB7cn0KY29sb3JzID0gYygncmVkJywnYmx1ZScsJ2dyZWVuJykKY190eXBlcyA9IGMoJ0hpZXJhcmNoaWNhbCBDbHVzdGVyaW5nJywnUGFydGl0aW9uYWwgQ2x1c3RlcmluZycsJ0sgTWVhbnMgQ2x1c3RlcmluZycpCnRfdHlwZXMgPSBjKCdSYXcnLCAnTWluLU1heCBTY2FsaW5nJywnWi1TY29yZSBOb3JtYWxpemF0aW9uJykKYGBgCgpgYGB7cn0KaW5kZXhfYWxsID0gYyhpbmRleF9oaWVyX3JhdyxpbmRleF9oaWVyX3NjYWxlZCxpbmRleF9oaWVyX3pzY29yZSwgaW5kZXhfcGFyX3JhdywgaW5kZXhfcGFyX3NjYWxlZCwgaW5kZXhfcGFyX3pzY29yZSwgaW5kZXhfa21lYW5zX3JhdywgaW5kZXhfa21lYW5zX3NjYWxlZCwgaW5kZXhfa21lYW5zX3pzY29yZSkKCnBsb3QoaW5kZXhfYWxsLHhheHQ9J24nLHR5cGU9J2gnLCBjb2wgPSBjb2xvcnMsIHhsYWI9IkNsdXN0ZXJpbmcgTWV0aG9kcyIsIHlsYWI9IkFSQU5ESSBNZWFzdXJlIiwgbWFpbj0nQWRqdXN0ZWQgUmFuZG9tIEluZGV4OiBIaWVyYXJjaGljYWwsIFBhcnRpdGlvbmFsICYgSy1NZWFucyBDbHVzdGVyaW5nJywgbHdkPTQpCmF4aXMoMSwgYXQ9c2VxKDIsOSxieT0zKSwgbGFiZWxzPWNfdHlwZXNbMTozXSkKbGVnZW5kKCJ0b3ByaWdodCIsdF90eXBlcywgY29sID0gY29sb3JzLCB0aXRsZSA9ICdUcmFuc2Zvcm1hdGlvbiBUeXBlcycsIGx3ZD0yLGNleD0uNzUpCmBgYAoKYGBge3J9CnVuYWRqdXN0ZWRfYWxsID0gYyh1bmFkanVzdGVkX2hpZXJfcmF3LCB1bmFkanVzdGVkX2hpZXJfc2NhbGVkLCB1bmFkanVzdGVkX2hpZXJfenNjb3JlLCB1bmFkanVzdGVkX3Bhcl9yYXcsIHVuYWRqdXN0ZWRfcGFyX3NjYWxlZCwgdW5hZGp1c3RlZF9wYXJfenNjb3JlLCB1bmFkanVzdGVkX2ttZWFuc19yYXcsIHVuYWRqdXN0ZWRfa21lYW5zX3NjYWxlZCwgdW5hZGp1c3RlZF9rbWVhbnNfenNjb3JlKQoKcGxvdCh1bmFkanVzdGVkX2FsbCx4YXh0PSduJyx0eXBlPSdoJywgY29sID0gY29sb3JzLCB4bGFiPSJDbHVzdGVyaW5nIE1ldGhvZHMiLCB5bGFiPSJVbmFkanVzdGVkIFJhbmRvbSBJbmRleCIsIG1haW49J1VuYWRqdXN0ZWQgSW5kZXg6IEhpZXJhcmNoaWNhbCwgUGFydGl0aW9uYWwgJiBLLU1lYW5zIENsdXN0ZXJpbmcnLCBsd2Q9NCkKYXhpcygxLCBhdD1zZXEoMiw5LGJ5PTMpLCBsYWJlbHM9Y190eXBlc1sxOjNdKQpsZWdlbmQoInRvcHJpZ2h0Iix0X3R5cGVzLCBjb2wgPSBjb2xvcnMsIHRpdGxlID0gJ1RyYW5zZm9ybWF0aW9uIFR5cGVzJywgbHdkPTIsIGNleD0wLjc1KQpgYGAKCgo=